package com.jboom.jboomconverter.util;

import com.google.common.collect.Lists;
import com.jboom.jboomconverter.annotation.Convert;
import com.jboom.jboomconverter.annotation.Converter;
import com.squareup.javapoet.*;

import javax.annotation.processing.Messager;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhangwen
 * @date 2023/5/27 23:13
 */
public class ConverterGen {

    private Elements elementUtil;

    private Messager messager;

    private static final String LIST_TYPE = List.class.getCanonicalName();
    private static final String SET_TYPE = Set.class.getCanonicalName();
    private static final String MAP_TYPE = Map.class.getCanonicalName();
    private static final String STRING_TYPE = String.class.getCanonicalName();
    private static final String DATE_TYPE = Date.class.getCanonicalName();
    private static final String LOCAL_DATE_TYPE = LocalDate.class.getCanonicalName();
    private static final String LOCAL_DATE_TIME_TYPE = LocalDateTime.class.getCanonicalName();
    private static final String LOCAL_TIME_TYPE = LocalTime.class.getCanonicalName();

    private static final String CONVERTER_FIELD_NAME = "customizeConverter";


    /**
     * 方法名  入参  出差
     */
    private Map<String, Map<TypeMirror, TypeMirror>> CUSTOMIZE_DEFAULT_METHOD = new HashMap<>();

    /**
     * 自定义转换方法
     */
    private Map<String, Map<TypeMirror, TypeMirror>> CUSTOMIZE_CONVERTER_METHOD = null;

    /**
     * 自定义转换类
     */
    private String CUSTOMIZE_CONVERTER_METHOD_PATH = null;

    /**
     * 类全路径  入参 出参  自定义converter的方法
     */
    private static final Map<String, Map<String, Map<TypeMirror, TypeMirror>>> GLOBAL_CUSTOMIZE_CONVERTER_METHOD = new HashMap<>();


    public JavaFile genMapperImpl(Element element) {
        String packageName = this.elementUtil.getPackageOf(element).getQualifiedName().toString();
        String className = element.getSimpleName().toString();
        String targetPackage = packageName + ".impl";
        String targetClassName = className + "Impl";
        ClassName superClass = ClassName.get(packageName, className);
        parseConverterAnnotation(element);
        parseDefaultMethods(element);
        return JavaFile.builder(targetPackage, generate(element, targetClassName, superClass)).build();
    }

    private TypeSpec generate(Element element, String targetClassName, ClassName superClass) {
        TypeSpec.Builder builder = TypeSpec.classBuilder(targetClassName)
                .addModifiers(Modifier.PUBLIC)
                .addSuperinterface(superClass)
                .addMethod(emptyConstructor())
                .addMethods(generateMethods(element));
        if (isStrNotEmpty(CUSTOMIZE_CONVERTER_METHOD_PATH)) {
            builder.addField(generateClassField());
        }
        return builder.build();
    }

    /**
     * 生成方法
     *
     * @param element
     * @return
     */
    private List<MethodSpec> generateMethods(Element element) {
        List<MethodSpec> methodSpecs = Lists.newArrayList();
        List<? extends Element> childrenElements = element.getEnclosedElements();

        // convert注解的字段映射关系
        Map<String, Attr> relaMap = new HashMap<>();
        for (Element childrenElement : childrenElements) {
            // 只处理转换方法
            if (childrenElement.getKind() != ElementKind.METHOD ||
                    childrenElement.getModifiers().contains(Modifier.DEFAULT)) {
                continue;
            }
            ExecutableElement executableElement = (ExecutableElement) childrenElement;
            List<? extends VariableElement> parameters = executableElement.getParameters();
            // 暂时不处理多个参数的情况
            if (parameters.size() != 1) {
                continue;
            }

            parseConvertAnnotation(relaMap, childrenElement);

            String methodName = childrenElement.getSimpleName().toString();
            TypeMirror returnType = executableElement.getReturnType();
            TypeMirror paramType = parameters.get(0).asType();
            String paramName = parameters.get(0).getSimpleName().toString();
            // element用于获取 返回类型和参数类型中的字段
            TypeElement returnTypeElement = (TypeElement) ((DeclaredType) returnType).asElement();
            TypeElement paramTypeElement = (TypeElement) ((DeclaredType) paramType).asElement();

            MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(methodName)
                    .addAnnotation(Override.class)
                    .addModifiers(Modifier.PUBLIC)
                    .addParameter(ClassName.get(paramType), paramName)
                    .returns(ClassName.get(returnType));

            // 都是基本类型的话直接转换并return转换即可
            if (returnType.getKind().isPrimitive() || STRING_TYPE.equals(returnTypeElement.toString())) {
                methodBuilder.addCode(generatePrimitive(returnType, returnTypeElement, paramType, paramTypeElement, paramName));
            } else {
                // 返回的变量名
                String returnName = returnTypeElement.getSimpleName().toString().toLowerCase() + "R";
                methodBuilder.
                        addCode(generateConvertCodeBlock(returnType, returnTypeElement, paramType, paramTypeElement,
                                returnName, paramName, "", "", relaMap))
                        .addCode(CodeBlock.builder().addStatement("return " + returnName).build());
            }
            methodSpecs.add(methodBuilder.build());
            relaMap.clear();
        }
        return methodSpecs;
    }

    /**
     * 基本类型转换,最外层是基本类型直接 return即可
     *
     * @param returnType
     * @param returnTypeElement
     * @param paramType
     * @param paramTypeElement
     * @param paramName
     * @return
     */
    private String generatePrimitive(TypeMirror returnType, TypeElement returnTypeElement,
                                     TypeMirror paramType, TypeElement paramTypeElement,
                                     String paramName) {
        CodeBlock.Builder builder = CodeBlock.builder();
        // 基础类型转换，时间格式化，转String等
        if (returnType == paramType) {
            builder.addStatement("return " + paramName);
        } else if (STRING_TYPE.equals(returnTypeElement.toString())) {
            builder.addStatement("return $L.toString()", paramName);
        } else {
            builder.addStatement("return " + captureName(returnType.getKind().toString().toLowerCase()) + ".valueOf(" + paramName + ")");
        }
        return builder.build().toString();
    }

    private String generateConvertCodeBlock(TypeMirror returnType, TypeMirror paramType,
                                            String returnName, String paramName,
                                            String returnPathName, String paramPathName,
                                            Map<String, Attr> relaMap) {
        TypeElement returnTypeElement = (TypeElement) ((DeclaredType) returnType).asElement();
        TypeElement paramTypeElement = (TypeElement) ((DeclaredType) paramType).asElement();
        return generateConvertCodeBlock(returnType, returnTypeElement, paramType, paramTypeElement,
                returnName, paramName, returnPathName, paramPathName, relaMap);
    }


    /**
     * 生成转换代码块
     *
     * @param returnType
     * @param returnTypeElement
     * @param paramType
     * @param paramTypeElement
     * @param returnName
     * @param paramName
     * @param relaMap
     * @return
     */
    private String generateConvertCodeBlock(TypeMirror returnType, TypeElement returnTypeElement,
                                            TypeMirror paramType, TypeElement paramTypeElement,
                                            String returnName, String paramName,
                                            String returnPathName, String paramPathName,
                                            Map<String, Attr> relaMap) {

        CodeBlock.Builder builder = CodeBlock.builder();
        TypeName returnTypeName = ClassName.get(returnType);
        // 处理集合类
        if (returnType.getKind() == TypeKind.ARRAY) {
            TypeMirror returnTypeMirror = ((DeclaredType) returnType).getTypeArguments().get(0);
            TypeMirror paramTypeMirror = ((DeclaredType) paramType).getTypeArguments().get(0);
            return generateCollection(ArrayTypeName.of(returnTypeName), ArrayTypeName.of(returnTypeName), returnName, paramName, relaMap, returnTypeMirror, paramTypeMirror, builder);
        }
        if (LIST_TYPE.equals(returnTypeElement.toString())) {
            TypeMirror returnTypeMirror = ((DeclaredType) returnType).getTypeArguments().get(0);
            TypeMirror paramTypeMirror = ((DeclaredType) paramType).getTypeArguments().get(0);
            return generateCollection(ClassName.get(List.class), ClassName.get(ArrayList.class), returnName, paramName, relaMap, returnTypeMirror, paramTypeMirror, builder);
        }
        if (SET_TYPE.equals(returnTypeElement.toString())) {
            TypeMirror returnTypeMirror = ((DeclaredType) returnType).getTypeArguments().get(0);
            TypeMirror paramTypeMirror = ((DeclaredType) paramType).getTypeArguments().get(0);
            return generateCollection(ClassName.get(Set.class), ClassName.get(HashSet.class), returnName, paramName, relaMap, returnTypeMirror, paramTypeMirror, builder);
        }

        if (MAP_TYPE.equals(returnTypeElement.toString())) {
            // TODO  目前不处理MAP类型
            // 参数类型是map
            // 参数类型非map
            return "";
        }
        // 基本类型
        if (returnType.getKind().isPrimitive()) {
            // 类型相同，直接赋值即可
            if (returnType == paramType) {
                builder.addStatement("$T $L = $L", ClassName.get(returnType), returnName, paramName);
            } else {
                builder.addStatement("$T $L = $L", ClassName.get(returnType), returnName, captureName(returnType.getKind().toString().toLowerCase()) + ".valueOf(" + paramName + ")");
            }
        } else if (STRING_TYPE.equals(returnTypeElement.toString())) {
            // 转换为字符串类型
            builder.addStatement("$T $L = $L.toString()", ClassName.get(returnType), returnName, paramName);
        } else {
            // 引用类型，需要递归处理
            List<? extends Element> returnFieldElements = returnTypeElement.getEnclosedElements()
                    .stream().filter(element -> ElementKind.FIELD == element.getKind())
                    .collect(Collectors.toList());
            List<? extends Element> paramFieldElements = paramTypeElement.getEnclosedElements()
                    .stream().filter(element -> ElementKind.FIELD == element.getKind())
                    .collect(Collectors.toList());
            builder.addStatement("$T $L = new $T()", returnTypeName, returnName, returnTypeName)
                    .addStatement(generateGetSetMethod(returnFieldElements, paramFieldElements, returnName, paramName, returnPathName, paramPathName, relaMap));
        }
        return builder.build().toString();
    }


    /**
     * 生成getset方法
     *
     * @param returnFieldElements
     * @param paramFieldElements
     * @param returnVarName
     * @param paramName
     * @param relaMap
     * @return
     */
    private String generateGetSetMethod(List<? extends Element> returnFieldElements, List<? extends Element> paramFieldElements,
                                        String returnVarName, String paramName, String returnPathName, String paramPathName, Map<String, Attr> relaMap) {

        CodeBlock.Builder builder = CodeBlock.builder();
        Map<String, ? extends Element> pFieldMap = paramFieldElements.stream()
                .collect(Collectors.toMap(field -> field.getSimpleName().toString(), Function.identity()));

        for (Element returnFieldElement : returnFieldElements) {
            String rFieldName = returnFieldElement.getSimpleName().toString();
            String rPath = appendFieldName(returnPathName, rFieldName);
            String pFieldName = null;
            String pPath = null;
            Attr convertAnnAttr = relaMap.get(rPath);
            if (pFieldMap.containsKey(rFieldName)) {
                pFieldName = rFieldName;
                pPath = appendFieldName(paramPathName, pFieldName);
            } else if (Objects.nonNull(convertAnnAttr)) {
                pPath = convertAnnAttr.getSource();
                pFieldName = pPath.substring(pPath.lastIndexOf(".") + 1);
            }
            Element paramFieldElement = pFieldMap.get(pFieldName);
            TypeMirror rTypeMirror = returnFieldElement.asType();

            // 没有匹配的字段
            if (Objects.isNull(paramFieldElement)) {
                //  如果设置了默认值
                if (Objects.nonNull(convertAnnAttr) && Objects.nonNull(convertAnnAttr.getDefaultValue())) {
                    builder.addStatement("$L.set$L($L($L))",
                            returnVarName, captureName(rFieldName),
                            captureName(rTypeMirror.getKind().toString().toLowerCase()) + ".valueOf",
                            convertAnnAttr.getDefaultValue());
                    return builder.build().toString();
                }
                return "";
            }

            TypeMirror pTypeMirror = paramFieldElement.asType();
            // 1. 类型相同
            if (rTypeMirror == pTypeMirror) {
                builder.addStatement("$L.set$L($L.get$L())",
                        returnVarName, captureName(rFieldName), paramName, captureName(pFieldName));
            } else {
                // 2. 类型不同，但是基本类型
                if (rTypeMirror.getKind().isPrimitive() && pTypeMirror.getKind().isPrimitive()) {
                    //  直接调用对应的valueOf()
                    builder.addStatement("$L.set$L($L.valueOf($L.get$L()))",
                            returnVarName, captureName(rFieldName),
                            captureName(rTypeMirror.getKind().toString().toLowerCase()),
                            paramName, captureName(pFieldName));
                } else if (STRING_TYPE.equals(returnFieldElement.asType().toString())) {
                    // 3. 返回String，直接调用toString
                    if (Objects.nonNull(convertAnnAttr)) {
                        // 如果参数类型是date,且自定义了转换格式
                        TypeElement pTypeElement = (TypeElement) ((DeclaredType) pTypeMirror).asElement();
                        if (isStrNotEmpty(convertAnnAttr.getDateFormat())) {
                            if (DATE_TYPE.equals(pTypeElement.toString())) {
                                builder.addStatement("$T formatter = new  $T($S)", ClassName.get(SimpleDateFormat.class), ClassName.get(SimpleDateFormat.class), convertAnnAttr.getDateFormat())
                                        .addStatement("$T $L  = formatter.format($L.get$L())", ClassName.get(String.class), rFieldName, paramName, captureName(pFieldName));
                            } else if (LOCAL_DATE_TYPE.equals(pTypeElement.toString())
                                    || LOCAL_DATE_TIME_TYPE.equals(pTypeElement.toString())
                                    || LOCAL_TIME_TYPE.equals(pTypeElement.toString())) {
                                builder.addStatement("$T formatter = $T.ofPattern($S)", ClassName.get(DateTimeFormatter.class), ClassName.get(DateTimeFormatter.class), convertAnnAttr.getDateFormat())
                                        .addStatement("$T $L  = formatter.format($L.get$L())", ClassName.get(String.class), rFieldName, paramName, captureName(pFieldName));
                            }
                        }
                        // 如果自定义转换
                        customizeCode(returnVarName, paramName, builder, rFieldName, pFieldName, convertAnnAttr, rTypeMirror, pTypeMirror);
                    } else {
                        builder.addStatement("$L.set$L($L.get$L().toString())",
                                returnVarName, captureName(rFieldName), paramName, captureName(pFieldName));
                    }
                } else if (MAP_TYPE.equals(returnFieldElement.asType().toString())) {
                    // TODO  目前不处理MAP类型
                    // 返回类型是map
                    //  1. 参数类型是map a.putAll(b);
                    //  2. 参数类型为引用类型，非MAP  遍历属性字段 a.put(key,b.getKey()),需要
                } else {
                    // 3. 类型不同
                    String cRTypeVarName = returnFieldElement.getSimpleName().toString().toLowerCase() + "R";
                    String cRFieldName = paramName + ".get" + captureName(pFieldName) + "()";
                    // 如果自定义转换
                    if (Objects.nonNull(convertAnnAttr)) {
                        customizeCode(returnVarName, paramName, builder, rFieldName, pFieldName, convertAnnAttr, rTypeMirror, pTypeMirror);
                    } else {
                        builder.addStatement(generateConvertCodeBlock(rTypeMirror, pTypeMirror, cRTypeVarName, cRFieldName,
                                rPath, pPath, relaMap));
                        builder.addStatement("$L.set$L($L)",
                                returnVarName, captureName(rFieldName), cRTypeVarName);
                    }
                }
            }
        }
        return builder.build().toString();
    }

    private static String appendFieldName(String pre, String next) {
        if (isStrNotEmpty(pre)) {
            return pre + "." + next;
        } else {
            return next;
        }
    }

    private void customizeCode(String returnVarName, String paramName, CodeBlock.Builder builder, String rFieldName, String pFieldName, Attr convertAnnAttr, TypeMirror rTypeMirror, TypeMirror pTypeMirror) {
        String customizeMethod = convertAnnAttr.getCustomizeMethod();
        if (isStrNotEmpty(customizeMethod)) {
            Map<TypeMirror, TypeMirror> defaultTypeMirrorMap = CUSTOMIZE_DEFAULT_METHOD.getOrDefault(customizeMethod, new HashMap<>());
            if (defaultTypeMirrorMap.get(pTypeMirror) == rTypeMirror) {
                builder.addStatement("$L.set$L(this.$L($L.get$L()))", returnVarName, captureName(rFieldName), customizeMethod, paramName, captureName(pFieldName));
            } else {
                Map<TypeMirror, TypeMirror> classTypeMirrorMap = CUSTOMIZE_CONVERTER_METHOD.getOrDefault(customizeMethod, new HashMap<>());
                if (classTypeMirrorMap.get(pTypeMirror) == rTypeMirror) {
                    builder.addStatement("$L.set$L($L.$L($L.get$L()))", returnVarName, captureName(rFieldName),
                            CONVERTER_FIELD_NAME, customizeMethod, paramName, captureName(pFieldName));
                }
            }
        }
    }

    private static boolean isStrNotEmpty(String str) {
        return str != null && str.length() > 0;
    }

    /**
     * 处理集合类型
     *
     * @param pClazz
     * @param nClazz
     * @param returnName
     * @param paramName
     * @param relaMap
     * @param listReturnType
     * @param listParamType
     * @param builder
     * @return
     */
    private String generateCollection(TypeName pClazz, TypeName nClazz, String returnName, String paramName, Map<String, Attr> relaMap, TypeMirror listReturnType, TypeMirror listParamType, CodeBlock.Builder builder) {
        if (pClazz instanceof ArrayTypeName) {
            builder.addStatement("$T $L = new $T()",
                    pClazz,
                    returnName,
                    nClazz);
        } else {
            builder.addStatement("$T $L = new $T()",
                    ParameterizedTypeName.get((ClassName) pClazz, ClassName.get(listReturnType)),
                    returnName,
                    nClazz);
        }
        builder
                .beginControlFlow("for($T p : $L)", ClassName.get(listParamType), paramName)
                .addStatement(generateConvertCodeBlock(listReturnType, listParamType, "r", "p", "", "", relaMap))
                .addStatement("$L.add(r)", returnName)
                .endControlFlow();
        return builder.build().toString();
    }

    /**
     * 添加自定义转换器成员变量
     *
     * @return
     */
    private FieldSpec generateClassField() {
        int lastIndex = CUSTOMIZE_CONVERTER_METHOD_PATH.lastIndexOf(".");
        return FieldSpec.builder(ClassName.get(CUSTOMIZE_CONVERTER_METHOD_PATH.substring(0, lastIndex),
                CUSTOMIZE_CONVERTER_METHOD_PATH.substring(lastIndex + 1)), CONVERTER_FIELD_NAME, Modifier.PRIVATE).build();
    }

    /**
     * 首字母大写
     *
     * @param name
     * @return
     */
    public static String captureName(String name) {
        char[] cs = name.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

    /**
     * 自定义字段映射关系，或formmat方法
     *
     * @param relaMap
     * @param childrenElement
     */
    private void parseConvertAnnotation(Map<String, Attr> relaMap, Element childrenElement) {
        Convert[] converts = childrenElement.getAnnotationsByType(Convert.class);
        for (Convert convert : converts) {
            relaMap.put(convert.target(), new Attr(convert.source(), convert.dateFormat(), convert.defaultValue(), convert.customizeMethod()));
        }
    }

    /**
     * 空参构造函数
     *
     * @return
     */
    private MethodSpec emptyConstructor() {
        return MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .build();
    }

    /**
     * 接口中default的转换方法
     *
     * @param element
     */
    private void parseDefaultMethods(Element element) {
        List<? extends Element> childrenElements = element.getEnclosedElements();
        for (Element childrenElement : childrenElements) {
            if (childrenElement.getKind() == ElementKind.METHOD) {
                // 处理default方法
                if (childrenElement.getModifiers().contains(Modifier.DEFAULT)) {
                    ExecutableElement executableElement = (ExecutableElement) childrenElement;
                    List<? extends VariableElement> parameters = executableElement.getParameters();
                    // 暂时不处理多个参数的情况
                    if (parameters.size() != 1) {
                        continue;
                    }
                    String methodName = childrenElement.getSimpleName().toString();
                    Map<TypeMirror, TypeMirror> typeMirrorMap = CUSTOMIZE_DEFAULT_METHOD.get(methodName);
                    if (Objects.isNull(typeMirrorMap)) {
                        typeMirrorMap = new HashMap<>();
                        CUSTOMIZE_DEFAULT_METHOD.put(methodName, typeMirrorMap);
                    }
                    typeMirrorMap.put(parameters.get(0).asType(), executableElement.getReturnType());
                }
            }
        }
    }


    /**
     * 自定义转换器全路径
     *
     * @param element
     * @return
     */
    private void parseConverterAnnotation(Element element) {
        List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
        for (AnnotationMirror annotationMirror : annotationMirrors) {
            if (Converter.class.getName().equals(annotationMirror.getAnnotationType().toString())) {
                Set<? extends ExecutableElement> keySet = annotationMirror.getElementValues().keySet();
                for (ExecutableElement executableElement : keySet) {
                    // 自定义转换器
                    if (Objects.equals(executableElement.getSimpleName().toString(), "customizeConverter")) {
                        //  配置的类路径
                        this.CUSTOMIZE_CONVERTER_METHOD_PATH = annotationMirror.getElementValues().get(executableElement).getValue().toString();
                        this.CUSTOMIZE_CONVERTER_METHOD = GLOBAL_CUSTOMIZE_CONVERTER_METHOD
                                .getOrDefault(annotationMirror.getElementValues().get(executableElement).getValue().toString(),
                                        new HashMap<>());
                    }
                }
            }
        }
    }

    /**
     * 自定义转换类
     *
     * @param elements
     */
    public static void parseCustomizeConverter(Set<? extends Element> elements) {
        for (Element element : elements) {
            if (element.getKind() != ElementKind.METHOD) {
                continue;
            }
            String methodName = element.getSimpleName().toString();
            String className = element.getEnclosingElement().asType().toString();
            Map<String, Map<TypeMirror, TypeMirror>> methodTable = GLOBAL_CUSTOMIZE_CONVERTER_METHOD.get(className);
            if (Objects.isNull(methodTable)) {
                Map<String, Map<TypeMirror, TypeMirror>> initMap = new HashMap<>();
                GLOBAL_CUSTOMIZE_CONVERTER_METHOD.put(className, initMap);
                methodTable = initMap;
            }
            ExecutableElement executableElement = (ExecutableElement) element;
            List<? extends VariableElement> parameters = executableElement.getParameters();
            if (parameters.size() != 1) {
                // 暂时不处理多个参数的情况
                continue;
            }
            Map<TypeMirror, TypeMirror> typeMirrorMap = methodTable.get(methodName);
            if (Objects.isNull(typeMirrorMap)) {
                typeMirrorMap = new HashMap<>();
                methodTable.put(methodName, typeMirrorMap);
            }
            typeMirrorMap.put(parameters.get(0).asType(), executableElement.getReturnType());
        }
    }

    class Attr {
        String source;
        String dateFormat;
        String defaultValue;
        String customizeMethod;

        public Attr(String source, String dateFormat, String defaultValue, String customizeMethod) {
            this.source = source;
            this.dateFormat = dateFormat;
            this.defaultValue = defaultValue;
            this.customizeMethod = customizeMethod;
        }

        public String getDateFormat() {
            return dateFormat;
        }

        public void setDateFormat(String dateFormat) {
            this.dateFormat = dateFormat;
        }

        public String getDefaultValue() {
            return defaultValue;
        }

        public void setDefaultValue(String defaultValue) {
            this.defaultValue = defaultValue;
        }

        public String getCustomizeMethod() {
            return customizeMethod;
        }

        public void setCustomizeMethod(String customizeMethod) {
            this.customizeMethod = customizeMethod;
        }

        public String getSource() {
            return source;
        }

        public void setSource(String source) {
            this.source = source;
        }
    }


    public ConverterGen(Elements elementUtil, Messager messager) {
        this.elementUtil = elementUtil;
        this.messager = messager;
    }
}
